package site.sorghum.ddl.extra;

import lombok.extern.slf4j.Slf4j;
import site.sorghum.ddl.exception.DdlException;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * JDBC工具类
 *
 * @author sorghum
 */
@Slf4j
public class JdbcUtils {

    /**
     * 执行查询并返回单条记录(Map形式)
     *
     * @param dataSource 数据源
     * @param sql        SQL语句
     * @param params     参数列表
     * @return 单条记录的Map，键为列名，值为列值
     */
    public static Map<String, Object> queryForMap(DataSource dataSource, String sql, Object... params) {
        try (Connection conn = dataSource.getConnection()) {
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                setParameters(stmt, params);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        return resultSetToMap(rs);
                    }
                    return null;
                }
            }
        } catch (SQLException e) {
            throw new DdlException(e);
        }
    }

    /**
     * 执行查询并返回多条记录(List<Map>形式)
     *
     * @param dataSource 数据源
     * @param sql        SQL语句
     * @param params     参数列表
     * @return 多条记录的List，每个Map表示一条记录
     */
    public static List<Map<String, Object>> queryForList(DataSource dataSource, String sql, Object... params) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        try (Connection conn = dataSource.getConnection()) {
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                setParameters(stmt, params);
                try (ResultSet rs = stmt.executeQuery()) {
                    while (rs.next()) {
                        resultList.add(resultSetToMap(rs));
                    }
                }
            }
        } catch (SQLException e) {
            throw new DdlException(e);
        }
        return resultList;
    }

    /**
     * 执行更新操作(INSERT, UPDATE, DELETE)
     *
     * @param dataSource 数据源
     * @param sql        SQL语句
     * @param params     参数列表
     * @return 受影响的行数
     */
    public static int executeUpdate(DataSource dataSource, String sql, Object... params) {
        try (Connection conn = dataSource.getConnection()) {
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                setParameters(stmt, params);
                return stmt.executeUpdate();
            }
        } catch (SQLException e) {
            log.error("执行更新操作失败:{}", sql);
            throw new DdlException(e);
        }
    }

    /**
     * 设置PreparedStatement参数
     *
     * @param stmt   PreparedStatement
     * @param params 参数数组
     */
    private static void setParameters(PreparedStatement stmt, Object[] params) {
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                try {
                    stmt.setObject(i + 1, params[i]);
                } catch (SQLException e) {
                    throw new DdlException(e);
                }
            }
        }
    }

    /**
     * 将ResultSet转换为Map
     *
     * @param rs ResultSet
     * @return 包含列名和值的Map
     */
    private static Map<String, Object> resultSetToMap(ResultSet rs) {
        Map<String, Object> row = new HashMap<>();
        ResultSetMetaData metaData = null;
        try {
            metaData = rs.getMetaData();

            int columnCount = metaData.getColumnCount();

            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnLabel(i);
                Object value = rs.getObject(i);
                row.put(columnName, value);
            }
            return row;
        } catch (SQLException e) {
            throw new DdlException(e);
        }
    }

    /**
     * 安全关闭连接
     *
     * @param conn 要关闭的连接
     */
    public static void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new DdlException(e);
            }
        }
    }

    /**
     * 安全关闭Statement
     *
     * @param stmt 要关闭的Statement
     */
    public static void closeStatement(Statement stmt) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                throw new DdlException(e);
            }
        }
    }

    /**
     * 安全关闭ResultSet
     *
     * @param rs 要关闭的ResultSet
     */
    public static void closeResultSet(ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new DdlException(e);
            }
        }
    }
}